package com.woniuxy.book.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.woniuxy.book.entity.BookInfo;
import com.woniuxy.book.entity.BookType;
import com.woniuxy.book.entity.PageInfo;
import com.woniuxy.book.exception.booktype.BookTypeException;
import com.woniuxy.book.exception.booktype.BookTypeExceptionCode;
import com.woniuxy.book.mapper.BookInfoMapper;
import com.woniuxy.book.mapper.BookTypeMapper;
import com.woniuxy.book.param.booktype.AddBookTypeParam;
import com.woniuxy.book.param.booktype.SelectBookTypeParam;
import com.woniuxy.book.param.booktype.UpdateBookTypeParam;
import com.woniuxy.book.service.BookTypeService;
import com.woniuxy.book.service.dto.BookTypeDTO;
import com.woniuxy.book.service.dto.BookTypeTreeDTO;
import com.woniuxy.book.util.RedisKeyUtil;
import com.woniuxy.book.util.RedisUtil;
import com.woniuxy.book.util.StateData;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author li
 * @since 2024年2月09日
 */
@Service
public class BookTypeServiceImpl implements BookTypeService {

    @Resource
    private BookTypeMapper bookTypeMapper;

    @Resource
    private BookInfoMapper bookInfoMapper;

    @Resource
    private RedisUtil redisUtil;

    @Resource
    private ScheduledExecutorService scheduledExecutorService;

    @Override
    @Transactional
    public void addBookType(AddBookTypeParam param) {
        //前置删除
        redisUtil.delete(RedisKeyUtil.cacheBookTypeTree());
        //判断名称是否重复
        QueryWrapper<BookType> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("type_name", param.getTypeName());
        if (bookTypeMapper.selectOne(queryWrapper) != null) {
            throw new BookTypeException(BookTypeExceptionCode.BOOK_TYPE_EXCEPTION_TYPE_NAME_EXISTS);
        }
        //判断父类别是否存在
        if (param.getParentId() != 0) {
            BookType bookType = bookTypeMapper.selectById(param.getParentId());
            if (bookType == null) {
                throw new BookTypeException(BookTypeExceptionCode.BOOK_TYPE_EXCEPTION_PARENT_NOT_EXISTS);
            }
            //判断是否是叶子节点
            if (bookType.getTypeSelf() == StateData.SELF_YES) {
                bookType.setTypeSelf(StateData.SELF_NO);
                bookTypeMapper.updateById(bookType);
            }
        }
        //新增
        BookType type = BeanUtil.toBean(param, BookType.class);
        type.setTypeSelf(StateData.SELF_YES);
        type.setTypeState(StateData.BOOK_TYPE_STATE_NORMAL);
        bookTypeMapper.insert(type);
        //延迟删除
        scheduledExecutorService.schedule(new Runnable() {
            @Override
            public void run() {
                try {
                    redisUtil.delete(RedisKeyUtil.cacheBookTypeTree());
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        },60, TimeUnit.SECONDS);
        selectBookTypeTree(null);
    }

    @Override
    @Transactional
    public void enableBookType(Integer typeId) {
        //前置删除
        redisUtil.delete(RedisKeyUtil.cacheBookTypeTree());
        //类别是否存在
        BookType bookType = bookTypeMapper.selectById(typeId);
        if (bookType==null) {
            throw new BookTypeException(BookTypeExceptionCode.BOOK_TYPE_EXCEPTION_BOOKTYPE_NOT_EXISTS);
        }
        //是否已启用
        if (bookType.getTypeState()== StateData.BOOK_TYPE_STATE_NORMAL) {
            throw new BookTypeException(BookTypeExceptionCode.BOOK_TYPE_EXCEPTION_BOOKTYPE_HAS_ENABLED);
        }
        //是否被删除
        if (bookType.getTypeState()== StateData.BOOK_TYPE_STATE_DELETED) {
            throw new BookTypeException(BookTypeExceptionCode.BOOK_TYPE_EXCEPTION_BOOKTYPE_HAS_DELETED);
        }
        //启用
        bookType.setTypeState(StateData.BOOK_TYPE_STATE_NORMAL);
        bookTypeMapper.updateById(bookType);
        //同时启用所有父级类别
        enableParentBookType(bookType.getParentId());
        //启用该类别下的书籍
        UpdateWrapper<BookInfo> updateWrapper = new UpdateWrapper<>();
        updateWrapper.eq("type_id",bookType.getTypeId()).eq("book_state",StateData.BOOK_STATE_DISABLED);
        updateWrapper.set("book_state",StateData.BOOK_STATE_NORMAL);
        bookInfoMapper.update(null,updateWrapper);
        //延迟删除
        scheduledExecutorService.schedule(new Runnable() {
            @Override
            public void run() {
                try {
                    redisUtil.delete(RedisKeyUtil.cacheBookTypeTree());
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        },60, TimeUnit.SECONDS);
        selectBookTypeTree(null);
    }

    @Override
    @Transactional
    public void disableBookType(Integer typeId) {
        //前置删除
        redisUtil.delete(RedisKeyUtil.cacheBookTypeTree());
        //类别是否存在
        BookType bookType = bookTypeMapper.selectById(typeId);
        if (bookType==null) {
            throw new BookTypeException(BookTypeExceptionCode.BOOK_TYPE_EXCEPTION_BOOKTYPE_NOT_EXISTS);
        }
        //查看是否已禁用
        if (bookType.getTypeState()== StateData.BOOK_TYPE_STATE_DISABLED) {
            throw new BookTypeException(BookTypeExceptionCode.BOOK_TYPE_EXCEPTION_BOOKTYPE_HAS_DISABLED);
        }
        //是否被删除
        if (bookType.getTypeState()== StateData.BOOK_TYPE_STATE_DELETED) {
            throw new BookTypeException(BookTypeExceptionCode.BOOK_TYPE_EXCEPTION_BOOKTYPE_HAS_DELETED);
        }
        //先禁用当前类别
        bookType.setTypeState(StateData.BOOK_TYPE_STATE_DISABLED);
        bookTypeMapper.updateById(bookType);
        //查询出所有的正常子类别
        List<Integer> children = new ArrayList<>();
        findChild(bookType.getTypeId(),children,StateData.BOOK_TYPE_STATE_NORMAL);
        //children中保存了所有未被禁用的所有子类别
        //当前类别下的所有子类别禁用
        if (children.size()>0) {
            UpdateWrapper<BookType> updateWrapper = new UpdateWrapper<>();
            updateWrapper.in("type_id",children);
            updateWrapper.set("type_state",StateData.BOOK_TYPE_STATE_DISABLED);
            bookTypeMapper.update(null,updateWrapper);
        }
        //当前类别以及子类别的所有书籍禁用
        children.add(bookType.getTypeId());
        UpdateWrapper<BookInfo> wrapper = new UpdateWrapper<>();
        wrapper.in("type_id",children).eq("book_state",StateData.BOOK_STATE_NORMAL);
        wrapper.set("book_state",StateData.BOOK_STATE_DISABLED);
        bookInfoMapper.update(null,wrapper);
        //延迟删除
        scheduledExecutorService.schedule(new Runnable() {
            @Override
            public void run() {
                try {
                    redisUtil.delete(RedisKeyUtil.cacheBookTypeTree());
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        },60, TimeUnit.SECONDS);
        selectBookTypeTree(null);
    }

    @Override
    @Transactional
    public void updateBookType(UpdateBookTypeParam param) {
        //前置删除
        redisUtil.delete(RedisKeyUtil.cacheBookTypeTree());
        //是否存在
        BookType bookType = bookTypeMapper.selectById(param.getTypeId());
        if (bookType==null) {
            throw new BookTypeException(BookTypeExceptionCode.BOOK_TYPE_EXCEPTION_BOOKTYPE_NOT_EXISTS);
        }
        //是否异常
        if (bookType.getTypeState()!= StateData.BOOK_TYPE_STATE_NORMAL) {
            throw new BookTypeException(BookTypeExceptionCode.BOOK_TYPE_EXCEPTION_BOOKTYPE_NOT_NORMAL);
        }
        //类别名称是否已存在
        if (!bookType.getTypeName().equals(param.getTypeName())) {
            QueryWrapper<BookType> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("type_name",param.getTypeName());
            if (bookTypeMapper.selectOne(queryWrapper)!=null) {
                throw new BookTypeException(BookTypeExceptionCode.BOOK_TYPE_EXCEPTION_TYPE_NAME_EXISTS);
            }
        }
        //父级类别不存在 或异常
        if (param.getParentId()!=0) {
            BookType type = bookTypeMapper.selectById(param.getParentId());
            if (type ==null) {
                throw new BookTypeException(BookTypeExceptionCode.BOOK_TYPE_EXCEPTION_PARENT_NOT_EXISTS);
            }
            if (type.getTypeState()!= StateData.BOOK_TYPE_STATE_NORMAL) {
                throw new BookTypeException(BookTypeExceptionCode.BOOK_TYPE_EXCEPTION_BOOKTYPE_PARENT_NOT_NORMAL);
            }
        }
        //先查出原先的父类别
        if (bookType.getParentId()!=0) {
            //统计有多少个子类别
            BookType type = bookTypeMapper.selectById(bookType.getParentId());
            QueryWrapper<BookType> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("parent_id",type.getTypeId());
            Long count = bookTypeMapper.selectCount(queryWrapper);
            if (count.longValue()==1) {
                UpdateWrapper<BookType> updateWrapper = new UpdateWrapper<>();
                updateWrapper.set("type_self",StateData.SELF_YES);
                updateWrapper.eq("type_id",type.getTypeId());
                bookTypeMapper.update(null,updateWrapper);
            }
        }
        //更新当前类别
        BookType type = BeanUtil.toBean(param, BookType.class);
        bookTypeMapper.updateById(type);
        //查询新的父类别 是否为叶子节点
        if (param.getParentId()!=0) {
            BookType parent = bookTypeMapper.selectById(param.getParentId());
            if (parent.getTypeSelf()== StateData.SELF_YES) {
                parent.setTypeSelf(StateData.SELF_NO);
                bookTypeMapper.updateById(parent);
            }
        }
        //延迟删除
        scheduledExecutorService.schedule(new Runnable() {
            @Override
            public void run() {
                try {
                    redisUtil.delete(RedisKeyUtil.cacheBookTypeTree());
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        },60, TimeUnit.SECONDS);
        selectBookTypeTree(null);

    }

    @Override
    public PageInfo selectBookType(SelectBookTypeParam param) {
        QueryWrapper<BookType> queryWrapper = new QueryWrapper<>();
        //查看父类id 和 状态id 的搜索条件是否为空
        if (param.getTypeState()!=null) {
            queryWrapper.eq("type_state",param.getTypeState());
        }
        if (param.getParentId()!=null) {
            queryWrapper.eq("parent_id",param.getParentId());
        }
        //分页
        Page<BookType> page = new Page<>(param.getPageNum()==null?1:param.getPageNum(),param.getPageSize()==null?10: param.getPageSize());
        bookTypeMapper.selectPage(page,queryWrapper);
        PageInfo pageInfo = BeanUtil.toBean(page, PageInfo.class);
        List<BookTypeDTO> bookTypeDTOS = new ArrayList<>();
        for (BookType bookType : page.getRecords()) {
            BookTypeDTO bookTypeDTO = BeanUtil.toBean(bookType, BookTypeDTO.class);
            if (bookType.getParentId().longValue()!=0) {
                bookTypeDTO.setParentTypeName(bookTypeMapper.selectById(bookType.getParentId()).getTypeName());
            }else {
                bookTypeDTO.setParentTypeName("无父类");
            }
            bookTypeDTOS.add(bookTypeDTO);
        }
        pageInfo.setPages(page.getPages());
        pageInfo.setList(bookTypeDTOS);
        return pageInfo;
    }

    @Override
    public List<BookTypeTreeDTO> selectBookTypeTree(Integer typeState) {
        //先查询Redis中是否存在该数据
        List<BookTypeTreeDTO> cache = (List<BookTypeTreeDTO>) redisUtil.getObject(RedisKeyUtil.cacheBookTypeTree());
        if (cache!=null&&cache.size()>0) {
            if (typeState!=null) {
                Iterator<BookTypeTreeDTO> iterator = cache.iterator();
                while (iterator.hasNext()) {
                    BookTypeTreeDTO next = iterator.next();
                    if (next.getChildren()!=null) {
                        removeNotState(next.getChildren(),typeState);
                    }
                    if (next.getTypeState().intValue()!=typeState.intValue()) {
                        iterator.remove();
                    }
                }
            }
            return cache;
        }
        QueryWrapper<BookType> queryWrapper = new QueryWrapper<>();
        //先查询所有一级类别
//        if (typeState!=null) {
//            queryWrapper.eq("type_state",typeState);
//        }
        queryWrapper.eq("parent_id",0);
        List<BookType> bookTypes = bookTypeMapper.selectList(queryWrapper);
        //转型封装为DTO
        List<BookTypeTreeDTO> result = new ArrayList<>();
        if (bookTypes!=null&&bookTypes.size()>0) {
            for (BookType bookType : bookTypes) {
                BookTypeTreeDTO bookTypeTreeDTO = BeanUtil.toBean(bookType, BookTypeTreeDTO.class);
                bookTypeTreeDTO.setTypeSelf(bookType.getTypeSelf()==StateData.SELF_YES?true:false);
                findChild(bookTypeTreeDTO,typeState);
                result.add(bookTypeTreeDTO);
            }
        }
        BookTypeTreeDTO bookTypeTreeDTO = new BookTypeTreeDTO();
        bookTypeTreeDTO.setTypeId(0);
        bookTypeTreeDTO.setTypeSelf(true);
        bookTypeTreeDTO.setTypeName("无父类");
        bookTypeTreeDTO.setChildren(null);
        bookTypeTreeDTO.setTypeState(StateData.BOOK_TYPE_STATE_NORMAL);
        result.add(bookTypeTreeDTO);
        if (result.size()>0) {
            redisUtil.saveObject(RedisKeyUtil.cacheBookTypeTree(),result,24*60*60);
        }
        return result;
    }

    private void removeNotState(List<BookTypeTreeDTO> children, Integer typeState) {
        if (children==null) {
            return;
        }
        Iterator<BookTypeTreeDTO> iterator = children.iterator();
        while (iterator.hasNext()) {
            BookTypeTreeDTO next = iterator.next();
            if (next.getChildren()!=null) {
                removeNotState(next.getChildren(),typeState);
            }
            if (next.getTypeState().intValue()!=typeState.intValue()) {
                iterator.remove();
            }
        }
    }

    @Override
    @Transactional
    public void deleteBookType(Integer typeId) {
        //前置删除
        redisUtil.delete(RedisKeyUtil.cacheBookTypeTree());
        //类别是否存在
        BookType bookType = bookTypeMapper.selectById(typeId);
        if (bookType==null) {
            throw new BookTypeException(BookTypeExceptionCode.BOOK_TYPE_EXCEPTION_BOOKTYPE_NOT_EXISTS);
        }
        //是否被删除
        if (bookType.getTypeState()== StateData.BOOK_TYPE_STATE_DELETED) {
            throw new BookTypeException(BookTypeExceptionCode.BOOK_TYPE_EXCEPTION_BOOKTYPE_HAS_DELETED);
        }
        bookType.setTypeState(StateData.BOOK_TYPE_STATE_DELETED);
        bookTypeMapper.updateById(bookType);
        List<Integer> childrens = new ArrayList<>();
        //查找出所有子类
        findChild(typeId,childrens,null);
        if (childrens.size()>0) {
            UpdateWrapper<BookType> bookTypeUpdateWrapper = new UpdateWrapper<>();
            bookTypeUpdateWrapper.in("type_id",childrens);
            bookTypeUpdateWrapper.set("type_state",StateData.BOOK_TYPE_STATE_DELETED);
            bookTypeMapper.update(null,bookTypeUpdateWrapper);
        }
        childrens.add(typeId);
        //删除本类以及子类下的所有书籍
        UpdateWrapper<BookInfo> bookInfoUpdateWrapper = new UpdateWrapper<>();
        bookInfoUpdateWrapper.in("type_id",childrens);
        bookInfoUpdateWrapper.set("book_state",StateData.BOOK_STATE_DELETED);
        bookInfoMapper.update(null,bookInfoUpdateWrapper);
        //延迟删除
        scheduledExecutorService.schedule(new Runnable() {
            @Override
            public void run() {
                try {
                    redisUtil.delete(RedisKeyUtil.cacheBookTypeTree());
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        },60, TimeUnit.SECONDS);
        selectBookTypeTree(null);
    }

    @Override
    public List<BookType> selectAllSelf() {
        QueryWrapper<BookType> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("type_self",StateData.SELF_YES);
        return bookTypeMapper.selectList(queryWrapper);
    }

    @Override
    public void undeleteBookType(Integer typeId) {
        //前置删除
        redisUtil.delete(RedisKeyUtil.cacheBookTypeTree());
        //类别是否存在
        BookType bookType = bookTypeMapper.selectById(typeId);
        if (bookType==null) {
            throw new BookTypeException(BookTypeExceptionCode.BOOK_TYPE_EXCEPTION_BOOKTYPE_NOT_EXISTS);
        }
        //是否被删除
        if (bookType.getTypeState()!= StateData.BOOK_TYPE_STATE_DELETED) {
            throw new BookTypeException(BookTypeExceptionCode.BOOK_TYPE_EXCEPTION_BOOKTYPE_NOT_DELETED);
        }
        //启用
        bookType.setTypeState(StateData.BOOK_TYPE_STATE_NORMAL);
        bookTypeMapper.updateById(bookType);
        //同时启用所有父级类别
        undeleteParentBookType(bookType.getParentId());
        //启用该类别下的书籍
        UpdateWrapper<BookInfo> updateWrapper = new UpdateWrapper<>();
        updateWrapper.eq("type_id",bookType.getTypeId()).eq("book_state",StateData.BOOK_STATE_DELETED);
        updateWrapper.set("book_state",StateData.BOOK_STATE_DISABLED);
        bookInfoMapper.update(null,updateWrapper);
        //延迟删除
        scheduledExecutorService.schedule(new Runnable() {
            @Override
            public void run() {
                try {
                    redisUtil.delete(RedisKeyUtil.cacheBookTypeTree());
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        },60, TimeUnit.SECONDS);
        selectBookTypeTree(null);
    }

    @Override
    public List<Integer> findTypeArray(Integer parentId) {
        ArrayList<Integer> typeIds = new ArrayList<>();
        typeIds.add(parentId);
        BookType bookType = bookTypeMapper.selectById(parentId);
        if (bookType!=null) {
            findParentId(typeIds,bookType.getParentId());
        }
        Collections.reverse(typeIds);
        return typeIds;
    }

    private void findParentId(ArrayList<Integer> typeIds, Integer typeId) {
        BookType bookType = bookTypeMapper.selectById(typeId);
        if (bookType!=null) {
            typeIds.add(bookType.getTypeId());
            BookType bookType1 = bookTypeMapper.selectById(bookType.getParentId());
            if (bookType1!=null) {
                findParentId(typeIds,bookType1.getParentId());
            }
        }
    }

    private void undeleteParentBookType(Integer parentId) {
        //先修改当前父类别
        BookType bookType = bookTypeMapper.selectById(parentId);
        if (bookType!=null&&bookType.getTypeState()== StateData.BOOK_STATE_DELETED) {
            bookType.setTypeState(StateData.BOOK_TYPE_STATE_NORMAL);
            bookTypeMapper.updateById(bookType);
            //递归修改爷类别
            undeleteParentBookType(bookType.getParentId());
        }
    }

    /*
    * 递归查询某个类别下的所有子类别并保存到自己的children中
    * */
    private void findChild(BookTypeTreeDTO bookTypeTreeDTO, Integer typeState) {

        QueryWrapper<BookType> queryWrapper = new QueryWrapper<>();
//        if (typeState!=null) {
//            queryWrapper.eq("type_state",typeState);
//        }
        queryWrapper.eq("parent_id",bookTypeTreeDTO.getTypeId());
        List<BookType> bookTypes = bookTypeMapper.selectList(queryWrapper);
        if (bookTypes!=null&&bookTypes.size()>0) {
            bookTypeTreeDTO.setChildren(new ArrayList<>());
            for (BookType bookType : bookTypes) {
                BookTypeTreeDTO childrenDTO = BeanUtil.toBean(bookType, BookTypeTreeDTO.class);
                childrenDTO.setTypeSelf(bookType.getTypeSelf()==StateData.SELF_YES?true:false);
                bookTypeTreeDTO.getChildren().add(childrenDTO);
                //递归查找子类
                findChild(childrenDTO,typeState);
            }
        }
    }

    //查找出所有正常的子类
    private void findChild(Integer typeId, List<Integer> children,Integer state) {
        QueryWrapper<BookType> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("parent_id",typeId);
        if (state!=null) {
            queryWrapper.eq("type_state",StateData.BOOK_TYPE_STATE_NORMAL);
        }
        List<BookType> bookTypes = bookTypeMapper.selectList(queryWrapper);
        if (bookTypes!=null&&bookTypes.size()>0) {
            for (BookType bookType : bookTypes) {
                children.add(bookType.getTypeId());
                findChild(bookType.getTypeId(),children,StateData.BOOK_TYPE_STATE_NORMAL);
            }
        }
    }

    private void enableParentBookType(Integer parentId) {
        //先修改当前父类别
        BookType bookType = bookTypeMapper.selectById(parentId);
        if (bookType!=null&&bookType.getTypeState()== StateData.BOOK_STATE_DISABLED) {
            bookType.setTypeState(StateData.BOOK_TYPE_STATE_NORMAL);
            bookTypeMapper.updateById(bookType);
            //递归修改爷类别
            enableParentBookType(bookType.getParentId());
        }

    }


}
